package com.helloniu.docshare;

import java.io.File;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.helloniu.docshare.convert.DocumentConvertFacade;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;

import org.red5.io.amf3.ByteArray;

import com.helloniu.docshare.upload.BlockInfo;
import com.helloniu.docshare.upload.UploadInfo;
import com.helloniu.docshare.upload.Util;

/**
 * HttpActionController.
 *
 * @version   0.1.1
 * @author    Yuan Yuan
 */
public class HttpActionController extends MultiActionController {
    private final Log logger = LogFactory.getLog(getClass());//日志常量
    private FileSystemManager fileSystemManager = null;//文件管理者
    private DocumentConvertFacade documentConvertFacade = null;

    public void setFileSystemManager(FileSystemManager fileSystemManager) {
        this.fileSystemManager = fileSystemManager;
    }

    public void setDocumentConvertFacade(DocumentConvertFacade documentConvertFacade) {
        this.documentConvertFacade = documentConvertFacade;
    }

    // upload : /upload/?pres=aa.pdf&room=123
    /**
     * @brief <b>Summary:</b> {处理文件上传}
     *
     *        <b>Detail:</b>  {}
     *
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     *
     * @return ModelAndView
     * @throws Exception the exception
     *
     * @par 需求:
     *     REQ1.10[Tang]: svn://vobserver/tang/doc/SRS.doc
     *
     * @see
     */
    public ModelAndView processFileUpload(HttpServletRequest request, HttpServletResponse response) throws Exception {

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // MultipartFile is a copy of file in memory, not in file system
        MultipartFile multipartFile = multipartRequest.getFile("pres");
        // get Room ID from HttpServletRequest
        Integer room = new Integer(request.getParameterValues("room")[0]);
        Integer userID = new Integer(request.getParameterValues("userID")[0]);
        // @temp tonyy
        System.out.println("_________upload file--- room: " + room +" user: "+ userID);
        try {
            // save MultipartFile in server fileSystem by calling saveUploadedFile in FileSystemSlideManager class
            File file = this.fileSystemManager.saveUploadedFile(multipartFile, room, userID);


            // @temp tonyy
            // uploaded--> convert the file?
            documentConvertFacade.convert(file, room);
        }
        catch (IOException e) {
            logger.error("Failed to save file into filesystem.\n" + e.getMessage());
        }

        return new ModelAndView("upload", "room", room);
    }

    // getfile : /display?room=123&userID=1&fileTimestamp=1
    /**
     * @brief <b>Summary:</b> {从服务器取得文件}
     *
     *        <b>Detail:</b>  {}
     *
     * @param request HttpServletRequest
     * @param response HttpServletResponse where the image is sent
     * @return the model and view
     * @throws Exception the exception
     *
     * @par 需求:
     *     REQ1.10[Tang]: svn://vobserver/tang/doc/SRS.doc
     *
     * @see
     */
    public ModelAndView streamFileContent(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Integer room = new Integer(request.getParameterValues("room")[0]);
        Integer userID = new Integer(request.getParameterValues("userID")[0]);
        String fileTimestamp = request.getParameterValues("fileTimestamp")[0];
        //String fileName = request.getParameterValues("fileName")[0];
       // System.out.println("_________1_________LLLKK: " + room +"|"+ userID +"|"+ fileTimestamp );
        int pageIdx = -1;
        String prefix = "page";

        String[] vals = request.getParameterValues("page");

        if(vals == null || vals.length == 0) {
            vals = request.getParameterValues("thumbnail");
            prefix = "thumbnail";

            if(vals != null && vals.length > 0) {
                pageIdx = Integer.parseInt(request.getParameterValues("thumbnail")[0]);
            }
        }
        else {
            pageIdx = Integer.parseInt(request.getParameterValues("page")[0]);
        }

        if(pageIdx == -1) {
            // throw new RuntimeException("error page found!");
        }

        // page-1.
        // thumbnail-1.
        prefix = prefix + "-" + pageIdx + ".";
        response.setHeader("Cache-Control", "no-cache");

        // @temp tonyy, wait for lixiang.xu
        this.fileSystemManager.streamFile(room, userID, fileTimestamp,
            prefix, response.getOutputStream());
        //this.fileSystemManager.streamFile2(room, filename, page, response.getOutputStream());

        System.out.println("_______2___________LLLKK: " + room +"|"+ userID +"|"+ fileTimestamp +"|"+ prefix +"|"+ pageIdx);
        System.out.println("_______2___________LLLKK: " + prefix +"|"+ pageIdx +"|"+ System.currentTimeMillis());
        return null;
    }

    // @temp tonyy, to do
    // cancelUpload : /cancelUpload?room=123
    // cancelConvert : /cancelUpload?room=123




    // upload : /upload/?pres=aa.pdf&room=123
    /**
     * @brief <b>Summary:</b> {处理文件上传}
     *
     *        <b>Detail:</b>  {}
     *
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     *
     * @return ModelAndView
     * @throws Exception the exception
     *
     * @par 需求:
     *     REQ1.10[Tang]: svn://vobserver/tang/doc/SRS.doc
     *
     * @see
     */
    public ModelAndView processFileUpload2(HttpServletRequest request, HttpServletResponse response)
        throws Exception
    {
        if("POST".equals(request.getMethod())) {
            try {
                InputStream rin = request.getInputStream();

                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                byte[] buffer = new byte[128];
                int len = 0;

                while((len = rin.read(buffer)) >= 0) {
                    bytes.write(buffer, 0, len);
                }

                byte[] postBytes = bytes.toByteArray();


                ByteArray barr = new ByteArray();
                barr.writeBytes(postBytes);

                barr.position(0);
                String op = null;

                try {
                    op = Util.readString(barr);
                }
                catch(Throwable thr) {
                    logger.error("=====: " + thr);
                }

                if("getUploadInfo".equals(op)) {
                    String fileMD5ID = Util.readString(barr);
                    getUploadInfo(fileMD5ID, response);
                    return null;
                }
                else if("UploadFile".equals(op)) {
                    uploadFile(barr, response);
                    return null;
                }else if("CancelUploadFile".equals(op)){
                    String fileMD5ID = Util.readString(barr);
                    cancelUpload(fileMD5ID);
                    return null;
                }
                else {
                    throw new RuntimeException("not support operation");
                }
            }
            catch (IOException e) {
            }
        }

        return null;
    }

    private void cancelUpload(String fileMD5ID){
        //删除指定文件
        File file = new File("c:/"+fileMD5ID);
        File logfile = new File("c:/"+fileMD5ID+".cfg");

        if(file.exists()){
            file.delete();
        }

        if(logfile.exists()){
           boolean a =  logfile.delete();
        }
    }

    private synchronized void uploadFile(ByteArray barr, HttpServletResponse res) {
        barr.position(0);
        String header = Util.readString(barr);
        String fileMD5ID = Util.readString(barr);
        int threadID = barr.readInt();
        long endPos = Util.readLong(barr);
        long currPos = Util.readLong(barr);
        int blockSize = barr.readInt();
        byte[] bytes = new byte[blockSize];
        barr.readBytes(bytes);
        File file = getFileByMD5ID(fileMD5ID, true);

        try {
            RandomAccessFile filewriter = new RandomAccessFile(file, "rw");
            filewriter.seek(currPos);
            filewriter.write(bytes);
            filewriter.close();
        }
        catch (Exception e) {
            e.printStackTrace();
            return;
        }

        // write cfg file
        long startPos = currPos + blockSize;

        File cfgFile = new File("c:/" + fileMD5ID + ".cfg");
        Properties blocks = new Properties();

        boolean finished = startPos > endPos;

        // 文件上传完成
        if(cfgFile.exists()) {
            try {
                FileInputStream ins = new FileInputStream(cfgFile);
                blocks.load(ins);
                ins.close();
            }
            catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        String key = threadID + "";

        if(!finished) {
            blocks.setProperty(key, startPos + ":" + endPos);
        }
        else {
            if(blocks.containsKey(key)) {
                blocks.remove(key);
            }
        }

        // save cfg file
        if(blocks.isEmpty()) {
            file.delete();
            return;
        }

        try {
            FileOutputStream fout = new FileOutputStream(cfgFile, false);
            blocks.store(fout, "cfg file");
            fout.close();
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void getUploadInfo(String fileMD5ID, HttpServletResponse res) {
        UploadInfo info = getUploadInfo(fileMD5ID);

        ByteArray barr = new ByteArray();
        String header = "UploadInfo";
        Util.writeString(barr, header);
        barr.writeInt(info == null ? 0 : 1);

        if(info != null) {
            info.writeData(barr);
        }

        writeByteArrayToResponse(barr, res);
    }

    private UploadInfo getUploadInfo(String fileMD5ID) {
        File file = new File("c:/" + fileMD5ID);

        // 文件未上传
        if(!file.exists()){
            return null;
        }

        UploadInfo uploadInfo = new UploadInfo();
        uploadInfo.fileMD5ID = fileMD5ID;
        File cfgFile = new File("c:/" + fileMD5ID + ".cfg");

        // 文件上传完成
        if(!cfgFile.exists()){
            return uploadInfo;
        }

        // 文件未上传完, read cfg file
        Properties blocks = new Properties();

        try {
            FileInputStream ins = new FileInputStream(cfgFile);
            blocks.load(ins);
            ins.close();
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if(blocks.isEmpty()){
            return uploadInfo;
        }

        Iterator values = blocks.values().iterator();
        uploadInfo.blocks = new ArrayList<BlockInfo>();

        while(values.hasNext()) {
            String value = (String) values.next();

            BlockInfo blockInfo = new BlockInfo();
            blockInfo.parseData(value);
            uploadInfo.blocks.add(blockInfo);
        }

        return uploadInfo;
    }

    private void writeByteArrayToResponse(ByteArray arr, HttpServletResponse res) {
        int leng = arr.length();
        byte[] resarr = new byte[leng];
        arr.position(0);
        arr.readBytes(resarr);

        try {
            res.getOutputStream().write(resarr);
            res.getOutputStream().close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    private File getFileByMD5ID(String fileMD5ID) {
        return getFileByMD5ID(fileMD5ID, false);
    }

    private File getFileByMD5ID(String fileMD5ID, boolean create) {
        return new File("c:/" + fileMD5ID);
    }

}
